Skip to content

SSE update enhancements for multi-history view and published histories#22614

Merged
jmchilton merged 4 commits intogalaxyproject:devfrom
mvdbeek:sse_followup_1
May 1, 2026
Merged

SSE update enhancements for multi-history view and published histories#22614
jmchilton merged 4 commits intogalaxyproject:devfrom
mvdbeek:sse_followup_1

Conversation

@mvdbeek
Copy link
Copy Markdown
Member

@mvdbeek mvdbeek commented May 1, 2026

Three follow-ups making SSE history updates work everywhere the polling path used to cover.

  • Push SSE history updates to non-current multi-view panels — the SSE handler only refreshed the current history, so other panels in the multi-history view stayed stale once polling was disabled. It now iterates the changed history ids in the event and refreshes every one already tracked in storedHistories.

  • Make history refresh button SSE-aware — the refresh button's "last refreshed Xs ago" text and 2-minute red-stale cutoff were polling-era artifacts that misrepresented SSE state, and the click handler hit an idempotent no-op. Under SSE the title becomes "Refresh history", goes red only when the socket actually drops after a successful open (gated on a new sseEverConnected latch), and clicking forces a real refresh via refreshHistoryFromPush.

  • Push SSE history updates to non-owner viewers — owner dispatch keys on history ownership, so watching a shared or pinned non-owned history (multi-history view) silently received nothing. Adds an additive viewer-subscription channel: the client POSTs desired history ids to /api/events/history-subscriptions, the dispatcher fans the record out to every webapp worker over Kombu, and history_update fanout pushes to subscribed viewers alongside the owner. Subscriptions are refcounted client-side and replayed on every EventSource onopen so reconnects don't drop them; per-worker state is purged when a user's last connection on that worker closes. No authorization check on the dispatch path is needed — events only carry history ids and the client follows up with the normal access-controlled REST fetch.

How to test the changes?

(Select all options that apply)

  • I've included appropriate automated tests.
  • This is a refactoring of components with existing test coverage.
  • Instructions for manual testing are as follows:
    1. [add testing steps and prerequisites here if you didn't write automated tests covering all your changes]

License

  • I agree to license these and all my past contributions to the core galaxy codebase under the MIT license.

mvdbeek added 3 commits May 1, 2026 15:35
The history-store SSE handler only refreshed the current history. With
polling disabled under enable_sse_updates=true, other histories visible
in the multi-history view stayed stale until the user switched into
them. Iterate over all changed history ids in the SSE event and refresh
each one already tracked in storedHistories via updateContentStats and
historyItemsStore.fetchHistoryItems, so multi-view panels for
non-current histories pick up uploads as they happen.

Adds an integration_selenium test that uploads to a non-current history
through the API and asserts the new item renders in the multi-view
without a current-history switch — exercising the SSE-driven refresh
path end-to-end.
The refresh button's title and red-when-stale logic was designed for
the polling era and is misleading under SSE: lastCheckedTime only ticks
on real history changes (so the "Last refreshed Xs ago" text describes
nothing actionable), the 2-minute idle cutoff goes red even when SSE
is healthy, and the click handler called the idempotent
startWatchingHistory which short-circuits once initialized — clicking
did nothing.

In SSE mode the button now shows "Refresh history" with a normal link
variant, and only turns red ("Live updates disconnected. Click to
refresh.") when the SSE socket actually drops after a previous
successful open (gated on the new sseEverConnected latch in
useNotificationSSE so the brief initial-connect window isn't flagged
as an outage). Clicking now forces a real refresh via
refreshHistoryFromPush in both modes. Polling-mode title/variant is
unchanged.

Adds a HistoryCounter Vitest covering the SSE healthy / initial /
lost transitions plus the polling-mode legacy behavior.
Owner dispatch only delivers history_update events to the user who owns
the changed history. Watching a shared or pinned non-owned history
(e.g. via the multi-history view) silently received nothing under SSE
because the dispatch path keys on history ownership and there was no
way for a viewer to opt in.

Add an additive viewer-subscription channel: the client POSTs the
history ids it wants pushes for to /api/events/history-subscriptions,
the dispatcher fans the record out to every webapp worker over Kombu,
and history_update fanout pushes to subscribed viewers in addition to
the owner. Subscriptions are refcounted on the client and replayed on
every EventSource onopen so reconnects don't drop them. Per-worker
subscription state is purged when a user's last connection on that
worker closes; the client's onopen replay re-asserts the desired set.

No authorization check on the dispatch path: SSE events only carry
history ids, the client follows up with a normal access-controlled
REST fetch, and leaking "history changed at T" pings is acceptable.

MultipleViewItem now subscribes whenever it renders a history the
current user does not own and SSE is enabled; owned histories continue
through owner dispatch with zero subscribe round-trip.

Tests: integration test exercising subscribe -> mutate -> receive ->
unsubscribe -> stop receiving end-to-end, plus vitest for the client
refcount and replay logic.
@mvdbeek mvdbeek marked this pull request as ready for review May 1, 2026 16:56
@github-actions github-actions Bot added this to the 26.1 milestone May 1, 2026
@mvdbeek
Copy link
Copy Markdown
Member Author

mvdbeek commented May 1, 2026

Live on test.galaxyproject.org now, seems to work well.

@github-project-automation github-project-automation Bot moved this to Needs Review in Galaxy Dev - weeklies May 1, 2026
@jmchilton jmchilton merged commit 1af9307 into galaxyproject:dev May 1, 2026
62 of 63 checks passed
@github-project-automation github-project-automation Bot moved this from Needs Review to Done in Galaxy Dev - weeklies May 1, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

This PR was merged without a "kind/" label, please correct.

@nsoranzo nsoranzo deleted the sse_followup_1 branch May 1, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Development

Successfully merging this pull request may close these issues.

2 participants